﻿using System;
using System.IO;
using System.Net;
using System.Text;

using Mono.Options;

using octalforty.Componento.Core.ApplicationServices;
using octalforty.Componento.Impl;

using System.Linq;
using octalforty.Componento.Core.Util;

namespace octalforty.Componento.Commands
{
    [Command("list", Aliases = "ls")]
    public class ListCommand : ICommand
    {
        public class Options
        {
            public bool Local { get; set; }

            public bool Latest { get; set; }

            public string RepositoryAlias { get; set; }

            public bool Probe { get; set; }

            public string Proxy { get; set; }
        }

        public MetadirectoryManagerService MetadirectoryManager { get; set; }

        public PackageRepositoryBrowserService PackageRepositoryBrowser { get; set; }

        #region Implementation of ICommand
        public OptionSet GetOptionSet(object options)
        {
            throw new NotImplementedException();
        }

        public void Execute(string[] args)
        {
            var options = new Options { Local = false, RepositoryAlias = "default", Probe = true, Latest = false };
            var optionSet = new OptionSet {
                { "p|probe", "Specifies whether to probe directories for \"lib\". Default is \"true\".", p => options.Probe = p != null },
                { "l|local", "", l => options.Local = l != null },
                { "r:|repository:", "", r => options.RepositoryAlias = r },
                { "la|latest", "", la => options.Latest = la != null },
                { "proxy:", "", proxy => options.Proxy = proxy }
            };

            var rest = optionSet.Parse(args);

            if(!options.Proxy.IsNullOrEmpty())
                WebRequest.DefaultWebProxy = 
                    new WebProxy(options.Proxy.SubstringBefore(":"), int.Parse(options.Proxy.SubstringAfter(":")));
            
            if(options.Local)
            {
                
            } // if
            else
            {
                var repositoryUri = MetadirectoryManager.GetRepositoryUri(Directory.GetCurrentDirectory(), options.Probe, options.RepositoryAlias);
                Console.WriteLine("Listing remote packages from '{0}'{1}", repositoryUri, Environment.NewLine);

                var packages = PackageRepositoryBrowser.GetPackageManifests(repositoryUri, rest[0], null).OrderBy(p => p.Name).ThenByDescending(p => p.Version).AsEnumerable();
                if(options.Latest)
                    packages = packages.GroupBy(p => p.Name, p => p).Select(g => g.First());

                foreach(var package in packages)
                {
                    Console.Out.WriteLine(ConsoleColor.White, "  {0} {1}", package.Name, package.Version);
                    Console.WriteLine("{0}", Layout(package.Description, "    ", Console.WindowWidth - 10));

                    if(package.Dependencies.Count > 0)
                    {
                        Console.WriteLine();
                        Console.Out.WriteLine(ConsoleColor.White, "    Dependencies:");
                        foreach(var dependency in package.Dependencies)
                        {
                            Console.WriteLine("      {0} {1}", dependency.Name, dependency.Version);
                        } // foreach
                    } // if

                    Console.WriteLine();
                } // foreach
            } // else
        }

        private string Layout(string text, string prefix, int n)
        {
            if(text.Contains('\n'))
                return string.Join(Environment.NewLine + Environment.NewLine,
                    text.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries).
                    Select(l => Layout(l, prefix, n)).ToArray());

            var s = text.Split(' ');
            var r = new StringBuilder();
            var c = new StringBuilder(prefix);

            for(var j = 0; j < s.Length; ++j)
            {
                if(c.Length + s[j].Length > n)
                {   
                    r.Append(c.ToString()).AppendLine();
                    c = new StringBuilder(prefix);
                } // if

                c.Append(s[j] + ' ');
            } // for

            r.Append(c.ToString());

            return r.ToString();
        }
        #endregion
    }
}
